package service

import (
	"context"
	"crypto/sha512"
	"errors"
	"fmt"
	"github.com/anaskhan96/go-password-encoder"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"
	"mts/user_srv/form"
	"mts/user_srv/internal/domain"
	"mts/user_srv/internal/repository"
	"mts/user_srv/utils/rabbitmq"
	"strings"
	"time"
)

type UserService interface {
	GetUserList(ctx context.Context, req *domain.PageInfo) (*domain.UserListResponse, error)
	GetUserByMobile(ctx context.Context, req *domain.MobileRequest) (*domain.UserInfoResponse, error)
	UpdateUser(ctx context.Context, req *domain.UserUpdateForm, Role int32) (*emptypb.Empty, error)
	GetUserById(ctx context.Context, req *domain.IdRequest) (*domain.UserInfoResponse, error)
	CreateUser(ctx context.Context, req *domain.CreateUserInfo) (*domain.UserInfoResponse, error)
	CheckPassWord(ctx context.Context, req *domain.CheckPassWordInfo) (*domain.CheckResponse, error)
	DeleteUser(ctx context.Context, req *domain.IdRequest) (*emptypb.Empty, error)
	Publish(logData map[string]interface{}) error
	Count(ctx context.Context) (int, error)
	UpdatePassword(ctx *gin.Context, id int32, f *form.UpdatePasswordForm) error
}

// userServiceImpl 实现 UserService 接口
type userServiceImpl struct {
	repo repository.UserRepository
	rmq  *rabbitmq.RabbitMQ
}

func (u *userServiceImpl) UpdatePassword(ctx *gin.Context, id int32, f *form.UpdatePasswordForm) error {
	infoByUserId, err := u.repo.GetUserById(ctx, id)
	if err != nil {
		return err
	}
	rs, err := u.CheckPassWord(ctx, &domain.CheckPassWordInfo{
		Password:          f.OldPassword,
		EncryptedPassword: infoByUserId.PassWord,
	})
	if err != nil {
		return err
	}
	if !rs.Success {
		return fmt.Errorf("旧密码错误")
	}
	options := &password.Options{
		SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New,
	}
	salt, encodedPwd := password.Encode(f.NewPassword, options)
	newPassword := fmt.Sprintf("$pbkdf2-sha512$%s$%s", salt, encodedPwd)
	err = u.repo.UpdateUser(ctx, infoByUserId, map[string]interface{}{
		"PassWord": newPassword,
	})
	if err != nil {
		return err
	}
	return nil
}

func (u *userServiceImpl) Count(ctx context.Context) (int, error) {
	count, err := u.repo.Count(ctx)
	if err != nil {
		return 0, err
	}
	return count, nil
}

func (u *userServiceImpl) Publish(logData map[string]interface{}) error {
	logData["timestamp"] = time.Now()

	err := u.rmq.Publish(
		logData,
	)
	if err != nil {
		zap.S().Errorf("Error publishing log: %v", err)
		return err
	}
	return nil
}
func (u *userServiceImpl) DeleteUser(ctx context.Context, req *domain.IdRequest) (*emptypb.Empty, error) {
	err := u.repo.DeleteUser(ctx, req.ID)
	if err != nil {
		zap.S().Errorw("逻辑删除用户失败", "err", err)
		return nil, fmt.Errorf("逻辑删除用户失败: %v", err)
	}
	return &emptypb.Empty{}, nil
}

// NewUserService 返回 `UserService` 接口的实现
func NewUserService(repo repository.UserRepository, rmq *rabbitmq.RabbitMQ) UserService {
	return &userServiceImpl{repo: repo, rmq: rmq}
}

// GetUserList 方法实现
func (u *userServiceImpl) GetUserList(ctx context.Context, req *domain.PageInfo) (*domain.UserListResponse, error) {
	users, total, err := u.repo.GetUserList(ctx, req)
	if err != nil {
		zap.S().Errorw("[GetUserList] 查询 【用户列表】 失败", "err", err)
		return nil, fmt.Errorf("查询用户列表失败: %v", err)
	}
	rsp := &domain.UserListResponse{Total: int32(total)}
	for _, user := range users {
		rsp.Data = append(rsp.Data, *ModelToResponse(user))
	}
	return rsp, nil
}

func ModelToResponse(user domain.User) *domain.UserInfoResponse {
	userInfoRsp := domain.UserInfoResponse{
		ID:        user.ID,
		NickName:  user.NickName,
		Gender:    user.Gender,
		Role:      int32(user.Role),
		Mobile:    user.Mobile,
		IsDeleted: user.BaseModel.IsDeleted,
	}
	if user.Birthday != nil {
		userInfoRsp.BirthDay = uint64(user.Birthday.Unix())
	}
	return &userInfoRsp
}

func (u *userServiceImpl) GetUserByMobile(ctx context.Context, req *domain.MobileRequest) (*domain.UserInfoResponse, error) {
	user, err := u.repo.GetUserByMobile(ctx, req.Mobile)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("用户不存在")
		}
		return nil, fmt.Errorf("查询用户失败: %v", err)
	}
	return &domain.UserInfoResponse{
		ID:        user.ID,
		NickName:  user.NickName,
		Gender:    user.Gender,
		Role:      int32(user.Role),
		Mobile:    user.Mobile,
		PassWord:  user.PassWord,
		IsDeleted: user.BaseModel.IsDeleted,
	}, nil
}
func (u *userServiceImpl) GetUserById(ctx context.Context, req *domain.IdRequest) (*domain.UserInfoResponse, error) {
	user, err := u.repo.GetUserById(ctx, req.ID)
	if err != nil {
		return nil, err
	}
	userInfoRsp := ModelToResponse(*user)
	return userInfoRsp, nil
}

func (u *userServiceImpl) CreateUser(ctx context.Context, req *domain.CreateUserInfo) (*domain.UserInfoResponse, error) {
	options := &password.Options{
		SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New,
	}
	salt, encodedPwd := password.Encode(req.PassWord, options)
	newPassword := fmt.Sprintf("$pbkdf2-sha512$%s$%s", salt, encodedPwd)

	user := domain.User{
		Mobile:   req.Mobile,
		NickName: req.NickName,
		PassWord: newPassword,
	}
	err := u.repo.CreateUser(ctx, &user)
	if err != nil {
		if strings.Contains(err.Error(), "Duplicate entry") {
			return nil, fmt.Errorf("用户已存在")
		}
		return nil, fmt.Errorf("创建用户失败: %v", err)
	}

	userInfoRsp := ModelToResponse(user)
	return userInfoRsp, nil
}

func (u *userServiceImpl) UpdateUser(ctx context.Context, req *domain.UserUpdateForm, Role int32) (*emptypb.Empty, error) {
	user, err := u.repo.GetUserById(ctx, req.ID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("用户不存在")
		}
		return nil, fmt.Errorf("查询用户失败: %v", err)
	}

	updates := map[string]interface{}{}
	if Role == 2 {
		if req.NickName != "" {
			updates["NickName"] = req.NickName
		}
		if req.Gender != "" {
			updates["Gender"] = req.Gender
		}
		if req.BirthDay > 0 {
			timeStr := req.BirthDay * int64(time.Millisecond)
			birthDay := time.Unix(0, int64(timeStr))
			updates["Birthday"] = birthDay
		}
		if req.IsDeleted != nil {
			updates["IsDeleted"] = *req.IsDeleted
		}
		if req.Role == 1 || req.Role == 2 {
			updates["Role"] = req.Role
		}
	} else {
		if req.NickName != "" {
			updates["NickName"] = req.NickName
		}
		if req.Gender != "" {
			updates["Gender"] = req.Gender
		}
		if req.BirthDay > 0 {
			timeStr := req.BirthDay * int64(time.Millisecond)
			birthDay := time.Unix(0, int64(timeStr))
			updates["Birthday"] = birthDay
		}
	}

	err = u.repo.UpdateUser(ctx, user, updates)
	if err != nil {
		return nil, fmt.Errorf("更新用户失败: %v", err)
	}

	return &emptypb.Empty{}, nil
}

func (u *userServiceImpl) CheckPassWord(ctx context.Context, req *domain.CheckPassWordInfo) (*domain.CheckResponse, error) {
	options := &password.Options{
		SaltLen:      16,
		Iterations:   100,
		KeyLen:       32,
		HashFunction: sha512.New,
	}
	passwordInfo := strings.Split(req.EncryptedPassword, "$")
	if len(passwordInfo) < 4 {
		zap.S().Errorw("密码格式不正确", "encrypted_password", req.EncryptedPassword)
		return nil, fmt.Errorf("密码格式不正确: %v", req.EncryptedPassword)
	}
	check := password.Verify(req.Password, passwordInfo[2], passwordInfo[3], options)
	return &domain.CheckResponse{Success: check}, nil
}
